﻿namespace Bowlus.FrontEnd
{
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Diagnostics;
    using System;

    using Bowlus.Common;

    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;

    [ServiceContract(Namespace = "Bowlus.FrontEnd.AdminService")]
    public interface IAdminService
    {
        // Use WebInvoke to avoid server side cache (WebGet will use cache by default)

        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        string GetTenantDeployment();

        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        string GetApplications();

        // /AdminService.svc/CreateTenant/tenantId=trent/app=site1.3.zip
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, 
            UriTemplate = "CreateTenant/tenantId={tenantId}/app={app}")]
        string CreateTenant(string tenantId, string app);

        // /AdminService.svc/CreateTenant/tenantId=trent/app=site1.3.zip
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "Test/msg={msg}")]
        string Test(string msg);

        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "RemoveTenant/tenantId={tenantId}")]
        string RemoveTenant(string tenantId);

        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        string GetInstanceStatus();
    }

    public class AdminService : IAdminService
    {
        /*
         * Returns JSON:
         * [{"TenantId":"bhushan","HostName":"bhushan.thecloudsamurai.com","Application":"myapp1.2.zip","InstanceId":"Bowlus.AppHost_IN_0","Instance":"10.115.34.204","Status":"active","TargetInstance":"127.0.0.1","StandbyInstance":"","Timestamp":"\/Date(1318268345557)\/","PartitionKey":"_bowlus","RowKey":"bhushan"},
         * {"TenantId":"dan","HostName":"dan.thecloudsamurai.com","Application":"myapp1.2.zip","InstanceId":"Bowlus.AppHost_IN_1","Instance":"10.115.56.85","Status":"active","TargetInstance":"127.0.0.1","StandbyInstance":"","Timestamp":"\/Date(1318268345756)\/","PartitionKey":"_bowlus","RowKey":"dan"},
         * {"TenantId":"ercenk","HostName":"ercenk.thecloudsamurai.com","Application":"myapp1.1.zip","InstanceId":"Bowlus.AppHost_IN_2","Instance":"10.115.238.23","Status":"active","TargetInstance":"127.0.0.1","StandbyInstance":"","Timestamp":"\/Date(1318268345956)\/","PartitionKey":"_bowlus","RowKey":"ercenk"}]
         * */
        public string GetTenantDeployment()
        {
            var tenantDep = TentantDepTableContext.Instance.TDQueryable.ToList();

            var serializer =
                new System.Web.Script.Serialization.JavaScriptSerializer();

            return serializer.Serialize(tenantDep);
        }

        /*
         * return application list: site1.1.zip, site1.2.zip, ect...
         */ 
        public string GetApplications()
        {
            var container = BowlusSettings.StorageAccount.CreateCloudBlobClient().GetContainerReference(
                BowlusSettings.AppContainer);
            container.CreateIfNotExist();

            var blobs = container.ListBlobs();
            
            // Create a dictionary for dropdown list
            var dict = blobs.Select(app => Path.GetFileName(app.Uri.ToString())).ToDictionary(s => s);

            var appList = new System.Collections.ArrayList();
            foreach (var item in dict)
            {
                appList.Add(item.Value);
            }

            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();

            return serializer.Serialize(appList);
        }


        // Create new tenant in Tenant deployment table. This tenant will later be allocated a instance, and then be deployed.
        // tenantId='test1', application='site1.3.zip'
        public string CreateTenant(string tenantId, string application)
        {
            var ctx = TentantDepTableContext.Instance;
            var tenantDeployments = ctx.TDQueryable.ToList();

            var deployInstance = AppInstanceLocator.FindDeploymentSlot(tenantDeployments);

            var td = new TenantDeployment
            {
                TenantId = tenantId,
                HostName = BowlusSettings.TenantHostFromConfigFormat(tenantId),
                Application = application,
                AppCustom = string.Empty,
                Instance = string.Empty,
                InstanceId = string.Empty,
                Status = string.Empty,
                Staging = deployInstance,
                StagingId = string.Empty,
                SStatus = TenantDeployment.S_PROVISIONING,
            };

            try
            {
                ctx.AddTD(td);
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.Message + '\n' + ex.StackTrace);
                return "{\"status\":\"tenant may already exist.\"}";
            }

            (new NotifyModuleClient()).NotifyAllInstancesInAnotherRole("AppHostSync");
            
            return "{\"status\":\"ok\"}";
        }

        public string RemoveTenant(string tenantId)
        {
            var ctx = TentantDepTableContext.Instance;
            var tds = ctx.TDQueryable.ToList();
            
            foreach (var td in tds)
            {
                if (td.TenantId == tenantId)
                {
                    td.Status = TenantDeployment.S_REMOVE;
                    td.Staging = td.Instance;
                    td.SStatus = TenantDeployment.S_DEPROVISIONING;
                    ctx.UpdateTD(td);

                    (new NotifyModuleClient()).NotifyAllInstancesInAnotherRole("AppHostSync");

                    return "{\"status\":\"ok\"}";
                }
            }

            return string.Format("{\"status\":\"{0} not found.\"}", tenantId);
        }

        public string Test(string msg)
        {
            if (msg == null)
            {
            }
            else if (msg == "Rebalance")
            {
                FrontEndManager.Rebalance();
            }
            else if (msg == "AppHostSync")
            {
                (new NotifyModuleClient()).NotifyAllInstancesInAnotherRole("AppHostSync");
            }
            return "{\"status\":\"ok\"}";
        }

        /*
         * Get instance health status.
         */ 
        public string GetInstanceStatus()
        {
            var healthStatus = new HealthStatus()
            {
                ArrInstances = new List<InstanceState>(),
                AppHostInstances = new List<InstanceState>()
            };
            
            //TODO: Update this to use the service management API w/caching
            //RoleEnvironment information does not provide Status on an instance
            var roleInstances = RoleEnvironment.Roles[BowlusSettings.FrontEndRoleName];
            foreach (var instance in roleInstances.Instances)
            {
                healthStatus.ArrInstances.Add(new InstanceState() { Title = instance.Id, Status = "Ready" });
            }

            roleInstances = RoleEnvironment.Roles[BowlusSettings.AppHostRoleName];
            foreach (var instance in roleInstances.Instances)
            {
                var instanceState = new InstanceState() { Title = instance.Id, Status = "Ready" };
                healthStatus.AppHostInstances.Add(instanceState);

                var q = from td in TentantDepTableContext.Instance.TDQueryable where td.InstanceId == instance.Id select td;
                foreach (var td in q)
                {
                    instanceState.Items.Add(new InstanceStateItem() { Text = td.TenantId, Status = td.Status });
                }
            }

            var serializer =
                new System.Web.Script.Serialization.JavaScriptSerializer();

            return serializer.Serialize(healthStatus);
        }
    }
}
